/**********************************************************************************************/
/* Example.cpp															         			  */
/*                                                                       					  */
/* Copyright Paradigma, 1993-2005															  */
/* All Rights Reserved                                                   					  */
/**********************************************************************************************/

#include <stdafx.h>

#include <Examples.h>

// STD:
#include <string>
#include <vector>

using FBL::ulong;


/**********************************************************************************************/
std::string		Str2str( String );
std::string		center( String, int );


/**********************************************************************************************/
void Pause()
{
	std::cout << "\nPress Enter to finishing";

	std::string OK; 
	getline( std::cin, OK );
}

/**********************************************************************************************/
void Wait()
{
	std::cout << "\nPress Enter";

	std::string OK; 
	getline( std::cin, OK );
}

/**********************************************************************************************/
std::string	Str2str( String Str )
{
	std::string str;
	char c; UChar C;
	
	tslen len = Str.length();
	for( long i=0; i < len; i++ )
	{
		C = Str[i]; c = (char) C; str+=c;
	}
	
	return str;
}


/**********************************************************************************************/
std::string center( std::string str, int width )
{
	int len = (int) str.size();
	int left = (width - len) / 2;
	int right = width - len - left;
	
	std::string Out = "";
	
	Out += std::string(left, ' ');
	Out += str;
	Out += std::string(right, ' ');
	
	return Out;
}


/**********************************************************************************************/
// This code show table in console in nice form.
// Should be used only for VSDK examples, because it is not suited for big tables.
//
void ViewTable( I_Table_Ptr pT )
{
	BitSet_Ptr pSet = pT->SelectAllRecords();
	if( pSet )
		ViewSet(pT, pSet);
}


/**********************************************************************************************/
void ViewSet( I_Table_Ptr pT, BitSet_Ptr inSet )
{
	FBL::ushort FldIndex = 0;
	ulong		RecIndex = 0;

	ulong FldCount = pT->get_FieldCount();
	ulong RecCount = inSet->get_Count();

	cout << "\n";
	cout << "Table name: " << pT->get_Name().getBufferA() << "\n";

	if( FldCount == 0 ) 
		return;

	std::vector<ulong> len( FldCount + 1 ); 
	
	std::vector<std::string> rec( (RecCount + 1) * (FldCount + 1) + 1 ); 
	std::vector<std::string> out( RecCount + 2 );

	// for each field of table we get its name
	for( FldIndex = 1; FldIndex <= FldCount; ++FldIndex )
	{
		//I_Table_Ptr pTable = pFblDb->get_Table( tableName );
		I_Field_Ptr pFld = pT->get_Field( (FBL::ushort) FldIndex );
		
		if( pFld )
				rec[FldIndex - 1] = Str2str( pFld->get_Name() );
		else	rec[FldIndex - 1] = "<unknown>";			
	}	

	std::string tmp; 

	// loop to fill record by record, field by field.
	RecIndex = 0;	

	SetIterator_Ptr Iter = inSet->get_Iterator();
	REC_ID id = Iter->FirstItem();
	while( id > 0 )
	{
		++RecIndex; 
		
		ulong RecStart = RecIndex * FldCount;

		for( FldIndex = 1; FldIndex <= FldCount; ++FldIndex )
		{
			//I_Table_Ptr pTable = pFblDb->get_Table( tableName );
			I_Field_Ptr pFld = pT->get_Field( (FBL::ushort) FldIndex );

			pT->put_RecID( id );
			
			rec[RecStart + FldIndex - 1] = Str2str( pFld->get_Value()->get_String() );
		}

		id = Iter->NextItem();		
	}

	// loop: for each column we iterate all values to find maximal length:
	for( FldIndex = 1; FldIndex <= FldCount; ++FldIndex )
	{
		len[FldIndex - 1] = 0;
		
		// for each row including header
		for( RecIndex = 0; RecIndex <= RecCount; ++RecIndex )
		{
			ulong pos = RecIndex * FldCount + FldIndex - 1; 
		
			if( len[FldIndex - 1] < rec[pos].size() )
				len[FldIndex - 1] = (ulong) rec[pos].size();
		}
	}

		// loop: for each column we iterate all values to find maximal length:
	for( FldIndex = 1; FldIndex <= FldCount; ++FldIndex )
	{
		len[FldIndex - 1] = 0;
		
		// for each row including header
		for( RecIndex = 0; RecIndex <= RecCount; ++RecIndex )
		{
			ulong pos = RecIndex * FldCount + FldIndex - 1; 
		
			if( len[FldIndex - 1] < rec[pos].size() )
				len[FldIndex - 1] = (ulong) rec[pos].size();
		}
	}
	
	// loop: for each record we produce output string:
	for( RecIndex = 0; RecIndex <= RecCount; ++RecIndex )
	{
		out[RecIndex] = "! ";
		
		for( FldIndex = 1; FldIndex <= FldCount; ++FldIndex )
		{
			ulong pos = RecIndex * FldCount + FldIndex - 1; 

			std::string add = center( rec[pos], len[FldIndex - 1] );
			
			out[RecIndex] += add;
			out[RecIndex] += " ! ";
		}
	}

	std::cout << std::string(out[0].size() - 1, '=') << "\n";
	std::cout << out[0] << "\n";
	std::cout << std::string(out[0].size() - 1, '=') << "\n";
	
	for( RecIndex = 1; RecIndex <= RecCount; ++RecIndex )
	{
		std::cout << out[RecIndex] << "\n";
	}
	
	std::cout << std::string(out[0].size() - 1, '=') << "\n";
}


/**********************************************************************************************/
void ViewCursor( I_Cursor_Ptr inCursor )
{
	I_Table_Ptr pTable = fbl_dynamic_cast<I_Table>( inCursor );

	ViewTable( pTable );
}


#pragma mark -


/**********************************************************************************************/
void SQL_Execute( VSQL::I_SqlDatabase_Ptr pSqlDB, String query )
{
	SQL_Execute( pSqlDB, query, NULL );
}


/**********************************************************************************************/
void SQL_Execute( VSQL::I_SqlDatabase_Ptr pSqlDB, String query, ArrayOfValues_Ptr inBinds = 0 )
{
	cout << "\n\nQuery execution: \n" << query.getBufferA() << "\n";

	pSqlDB->SqlExecute( query, inBinds  );
}


/**********************************************************************************************/
void SQL_Select( VSQL::I_SqlDatabase_Ptr pSqlDB, String query )
{
    cout << "\n\nQuery execution: \n" << query.getBufferA() << "\n";

	VSQL::I_Cursor_Ptr pCursor = pSqlDB->SqlSelect( 
									query, VSQL::kClient, VSQL::kReadWrite, VSQL::kRandom );

	ViewCursor( pCursor );
}

/**********************************************************************************************/
void InitValentina(
	int inCacheSize )
{
  // if you want to run this example as LOCAL database then set gClient = false.
  // if you want to run this example as CLIENT database then set gClient = true.
  //
  // In the last case you must have VServer running.
  // VServer should have use with name "sa" and password "sa".
  // Or you need change login parameters in the CreateExampleDatabase() function.
  //
  
  gClient = false;
  
  // To use SSL set it to true
  gSSLEnable = false;

  if( gClient )
  {
	  ValentinaInitC();
	  gConn = CreateConnection ("localhost", "sa", "sa", "UTF-8" );
 	
	  if( gSSLEnable )
		  gConn->UseSSL();
	  gConn->Open();
  }
  else
  {
	ValentinaInit( inCacheSize );
  }
}


/**********************************************************************************************/
void InitValentina( )
{
	InitValentina( 4 * 1024 * 1024 );
}


/**********************************************************************************************/
FBL::I_Database_Ptr MakeNewDatabase( 
	EStorageType inType )
{
	if( gClient )
	{
		VSQL::I_SqlDatabase_Ptr pSqlDb = CreateSqlDatabase( gConn );

		FBL::I_Database_Ptr pFblDb = pSqlDb->get_BaseDatabase();

		return pFblDb;
	}
	else
	{
		VSQL::I_SqlDatabase_Ptr pSqlDb = CreateSqlDatabase( inType );
		FBL::I_Database_Ptr pFblDb = pSqlDb->get_BaseDatabase();

		return pFblDb;
	}
}


/**********************************************************************************************/
FBL::I_Database_Ptr MakeNewDatabase()
{
	return MakeNewDatabase( kStorage_Disk );
}


/**********************************************************************************************/
VSQL::I_SqlDatabase_Ptr MakeNewSqlDatabase( 
	EStorageType inType )
{
	if( gClient )
	{
		// prepare location:	
		VSQL::I_SqlDatabase_Ptr pSqlDb = CreateSqlDatabase( gConn );

		return pSqlDb;
	}
	else
	{
		VSQL::I_SqlDatabase_Ptr pSqlDb = CreateSqlDatabase( inType );

		return pSqlDb;
	}
}



/**********************************************************************************************/
VSQL::I_SqlDatabase_Ptr MakeNewSqlDatabase()
{
	return MakeNewSqlDatabase( kStorage_Disk );
}


/**********************************************************************************************/
void CreateExampleDatabase( 
	FBL::I_Database_Ptr inDb,
	const char* inDbName )
{
	if( gClient )
	{
		String p = ExtractNameFromFullPath( inDbName );
		inDb->put_Location( new Location( &p ) );
	}
	else
	{
		I_Location_Ptr pLocation = CreateDiskLocation( inDbName );
		inDb->put_Location( pLocation );		
	}
	inDb->Create();
}


/**********************************************************************************************/
void CreateExampleDatabase( 
	FBL::I_Database_Ptr inDb )
{
	CreateExampleDatabase( inDb, "test_db" );
}


/**********************************************************************************************/
void OpenDatabase( 
	FBL::I_Database_Ptr inDb,
	const char* inDbName )
{
	if( gClient )
	{
		// This is protection: to server should go just db name, without extension.
		// Some VSDK examples can have extensions. So we remove it here.
		//
		String p = ExtractNameFromFullPath( inDbName );
		inDb->put_Location( new Location( &p ) );
	}
	else
	{
		I_Location_Ptr pLocation = CreateDiskLocation( inDbName );
		inDb->put_Location( pLocation );
	}

	inDb->Open();
}


/**********************************************************************************************/
void OpenDatabase( 
	FBL::I_Database_Ptr inDb )
{
	OpenDatabase( inDb, "test_db" );
}


/**********************************************************************************************/
I_Connection_Ptr GetConnection()
{
	return gConn;
}


/**********************************************************************************************/
void ShutdownValentina()
{
	if( gClient )
	{
		gConn->Close();
		ValentinaShutDownC();
	}
	else
	{
		ValentinaShutDown();
	}
}



